import { Msger } from "./Msger";
import { GlobleValue, GameState, GameLocalStorage, GameData } from "./ComClass";
import BallSc from "./BallSc";

// Learn TypeScript:
//  - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/typescript.html
//  - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/reference/attributes.html
//  - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/life-cycle-callbacks.html
//  - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/life-cycle-callbacks.html

const { ccclass, property } = cc._decorator;

@ccclass
export default class MainSc extends cc.Component {

    @property(cc.Node)
    deadLine: cc.Node = null;
    @property(cc.Node)
    shotPoint: cc.Node = null;
    @property(cc.Node)
    ballsLayer: cc.Node = null;
    @property(cc.Node)
    aimLine: cc.Node = null;
    @property(cc.Node)
    brokenLine: cc.Node = null;
    @property(cc.Prefab)
    baseBall: cc.Prefab = null;
    // LIFE-CYCLE CALLBACKS:
    //保存初始的球体
    private beginBaseBalls: cc.Node[] = [];
    //private ballPool:cc.NodePool = new cc.NodePool();
    onLoad() {

    }
    initGame() {
        Msger.on(Msger.on_game_remove_ball, this.on_game_remove_ball, this);
        Msger.on(Msger.on_game_die, this.on_game_die, this);
        Msger.on(Msger.on_game_revive, this.on_game_revive, this);
        Msger.on(Msger.on_game_form_load, this.loadGameData, this);
        Msger.on(Msger.on_game_to_save, this.SaveGameData, this);

        Msger.on(Msger.on_game_reset_play, this.on_game_reset_play, this);
        this.node.getChildByName("bg main").on(cc.Node.EventType.TOUCH_START, this.ontouch_start, this);
        this.node.getChildByName("bg main").on(cc.Node.EventType.TOUCH_MOVE, this.ontouch_move, this);
        this.node.getChildByName("bg main").on(cc.Node.EventType.TOUCH_END, this.ontouch_end, this);

        cc.director.getCollisionManager().enabled = true;
        cc.director.getPhysicsManager().enabled = true;
        cc.director.getPhysicsManager().gravity = cc.v2(0, -200);
        let bits: any = cc.PhysicsManager.DrawBits;
        /* cc.director.getPhysicsManager().debugDrawFlags =
            bits.e_aabbBit 
            |
            bits.e_pairBit |
            bits.e_centerOfMassBit |
            bits.e_jointBit |
            bits.e_shapeBit
            ; */
        this.shotPoint.active = false;
        this.aimLine.active = false;
        this.brokenLine.active = false;
        //处理球
        for (let i = 0; i < this.ballsLayer.childrenCount; i++) {
            this.beginBaseBalls.push(this.ballsLayer.children[i]);
        }
        this.on_game_reset_play();
    }
    private resetBallsLayer() {
        for (let i = this.ballsLayer.childrenCount - 1; i >= 0; i--) {
            this.ballsLayer.children[i].destroy();
            //this.ballPool.put(this.ballsLayer.children[i]);
        }
        for (let i = 0; i < this.beginBaseBalls.length; i++) {
            let ball = cc.instantiate(this.beginBaseBalls[i]);
            this.ballsLayer.addChild(ball);
        }
        this.nextball = null;
    }
    nextball: cc.Node = null;
    private createBall() {
        let ball: cc.Node
        /* if (this.ballPool.size() > 0) { // 通过 size 接口判断对象池中是否有空闲的对象
            ball = this.ballPool.get();
            ball.getComponent(BallSc).init(true);
        } else { // 如果没有空闲对象，也就是对象池中备用对象不够时，我们就用 cc.instantiate 重新创建
            ball = cc.instantiate(this.baseBall);
        } */
        ball = cc.instantiate(this.baseBall);
        this.ballsLayer.addChild(ball);
        ball.position = this.shotPoint.position;
        this.nextball = ball;
        ball.getComponent(cc.RigidBody).gravityScale = 0;
        if (GameData.wannengSteps.indexOf(GameLocalStorage.gameData.shotStep) >= 0) {
            let ballsc = ball.getComponent(BallSc);
            ballsc.setBallType(1);
            BallSc.setHaveGiftIcon(ballsc);
        }
    }
    private touchID = -1;
    private ontouch_start(e: cc.Event.EventTouch) {
        if (GlobleValue.gameState != GameState.Runing) {
            return;
        }
        if (this.touchID != -1) {
            return;
        }
        this.aimLine.active = true;
        this.handleAimLineRotation(e);
    }
    private handleAimLineRotation(e) {
        let pos = this.node.convertToNodeSpaceAR(e.getLocation());
        this.touchID = e.getID();
        let v = pos.sub(this.aimLine.position);
        v = v.normalizeSelf();
        let angle = this.getAngle(-v.x, v.y);
        this.aimLine.rotation = angle - 90;
        if (v.y > 0) {
            this.aimLine.active = this.brokenLine.active = false;
        } else {
            this.aimLine.active = true;
        }
        if (this.aimLine.active) {
            this.checkRayCast(v);
        }
    }
    private checkRayCast(v: cc.Vec2) {
        this.brokenLine.active = false;
        this.aimLine.getComponent(cc.Sprite).fillRange = 1;
        let p1 = this.node.convertToWorldSpaceAR(this.aimLine.position);
        let p2 = this.node.convertToWorldSpaceAR(this.aimLine.position.add(new cc.Vec2(v.x * this.aimLine.height, v.y * this.aimLine.height)));
        let results = cc.director.getPhysicsManager().rayCast(p1, p2, cc.RayCastType.All);
        for (let i = 0; i < results.length; i++) {
            let result = results[i];
            let collider = result.collider;
            if (collider.node.group == "wall") {
                let point = result.point;
                let normal = result.normal;
                let fraction = result.fraction;
                this.brokenLine.position = this.node.convertToNodeSpaceAR(point);
                this.brokenLine.rotation = -this.aimLine.rotation;
                this.brokenLine.active = true;
                let d = this.getDistance(point.x, point.y, p1.x, p1.y);
                this.aimLine.getComponent(cc.Sprite).fillRange = d / this.aimLine.height;
            }
        }
        //console.log(v.x, v.y);
    }
    private ontouch_move(e: cc.Event.EventTouch) {
        if (GlobleValue.gameState != GameState.Runing) {
            return;
        }
        if (this.touchID == e.getID()) {
            this.handleAimLineRotation(e);
        }
    }
    private ontouch_end(e: cc.Event.EventTouch) {
        this.aimLine.active = false;
        this.brokenLine.active = false;
        if (GlobleValue.gameState != GameState.Runing) {
            return;
        }
        if (!this.nextball) {
            return;
        }
        let pos = e.getLocation();
        pos = this.ballsLayer.convertToNodeSpaceAR(pos);
        if (pos.y > this.deadLine.y) {
            this.touchID = -1;
            return;
        }
        let v = pos.sub(this.shotPoint.getPosition());
        v = v.normalizeSelf();
        let ball = this.nextball;
        ball.getComponent(cc.RigidBody).gravityScale = 1;
        ball.getComponent(cc.RigidBody).linearVelocity = cc.v2(v.x * 900, v.y * 900);
        this.nextball = null;
        this.touchID = -1;
        GameLocalStorage.gameData.shotStep += 1;
        
    }
    private getAngle(ox, oy): number {
        return Math.atan2(oy, ox) * 180 / Math.PI;
    }
    private getDistance(x1, y1, x2, y2): number {
        return Math.floor(Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
    }
    private createBallCoolDown = 0;
    update(dt) {
        if (!this.nextball) {
            this.createBallCoolDown += dt;
            if (this.createBallCoolDown >= 0.45) {
                this.createBallCoolDown = 0;
                this.createBall();
            }
        }
    }
    private on_game_reset_play() {
        GameLocalStorage.gameData.currentScore = 0;
        this.ballsLayer.removeAllChildren();
        this.resetBallsLayer();
        this.createBall();
        //重置分数
        Msger.emit(Msger.on_reset_score);
        //重置进度条
        Msger.emit(Msger.on_level_progress_zero);
        GameLocalStorage.gameData.wannengprop = 1;
        GameLocalStorage.gameData.wannenggetcount = 0;
        GameLocalStorage.gameData.reviveTimes = 1;

        Msger.emit(Msger.on_show_help_hand);
    }
    private on_game_revive() {
        for (let i = this.ballsLayer.childrenCount - 1; i >= 0; i--) {
            let ball = this.ballsLayer.children[i];
            if (ball == this.nextball) {
                continue;
            }
            if (ball.y >= this.deadLine.y - 200) {
                ball.destroy();
            }
        }
        GlobleValue.gameState = GameState.Runing;
    }
    private on_game_die() {
        for (let i = this.ballsLayer.childrenCount - 1; i >= 0; i--) {
            let ball = this.ballsLayer.children[i];
            if (ball == this.nextball) {
                continue;
            }
            let ballsc = ball.getComponent(BallSc);
            if (ballsc) {
                if (ballsc.shoting) {
                    ball.destroy();
                }
            }
            if (ball.y > this.deadLine.y - 100) {
                ball.destroy();
            }
        }
    }
    public on_game_remove_ball(ball) {
        /* this.ballPool.put(ball);
        ball.getComponent(cc.RigidBody).gravityScale = 0;
        ball.getComponent(cc.RigidBody).linearVelocity = cc.v2(); */
        ball.destroy();
    }
    handle_click_game_over() {
        console.log("Game Over");
        GlobleValue.gameState = GameState.Over;
        //GameLocalStorage.gameData.reviveTimes = 1;
        Msger.emit(Msger.on_game_die);
    }
    private loadGameData() {
        if (GameLocalStorage.gameData.gameSave) {
            this.ballsLayer.removeAllChildren(true);
            if (GameLocalStorage.gameData.gameSave.balls) {
                for (let balldata of GameLocalStorage.gameData.gameSave.balls) {
                    let ball = cc.instantiate(this.baseBall);
                    let ballsc = ball.getComponent(BallSc);
                    if (ballsc) {
                        ballsc.setBallType(balldata.type);
                        ballsc.size = balldata.size;
                        ballsc.updateSize();
                        ball.x = balldata.x;
                        ball.y = balldata.y;
                    }
                    this.ballsLayer.addChild(ball);
                }
            }
            if (GameLocalStorage.gameData.gameSave.next) {
                let nextdata = GameLocalStorage.gameData.gameSave.next;
                if (this.nextball) {
                    let nextballsc = this.nextball.getComponent(BallSc);
                    nextballsc.setBallType(nextdata.type);
                    nextballsc.size = nextdata.size;
                    nextballsc.updateSize();
                    this.nextball.parent = this.ballsLayer;
                }
            }
            Msger.emit(Msger.on_level_progress_update);
        }
    }
    private SaveGameData() {
        let nextdata = { type: 0, size: 1 };
        if (this.nextball) {
            let nextballsc = this.nextball.getComponent(BallSc);
            nextdata.size = nextballsc.size;
            nextdata.type = nextballsc.ballType;
            this.nextball.getComponent(cc.RigidBody).gravityScale = 0;
        }
        let ballsdata: any[] = [];
        for (let ball of this.ballsLayer.children) {
            if (ball == this.nextball) {
                continue;
            }
            let ballsc = ball.getComponent(BallSc);
            if (ballsc) {
                let balldata = { type: ballsc.ballType, size: ballsc.size, x: ball.x, y: ball.y };
                ballsdata.push(balldata);
            }
        }
        GameLocalStorage.gameData.gameSave = { next: nextdata, balls: ballsdata };
        GameLocalStorage.Save();
    }
}
